#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Time    : 2025/4/7 下午9:17
@Author  : Suger
@File    : base.py
@Desc    : 
"""
import os
import random
import shutil
import tempfile
import time
import traceback
from abc import ABC
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path
from typing import *

from moviepy.editor import *

from log import log
from core.video.processor import (batch_merge_videos, batch_clip_video, batch_resize_videos, batch_set_video_cover,
                                  batch_speed_up_videos,
                                  batch_set_srt_to_video, batch_set_subtitle_to_video, batch_set_background_music_to_video,
                                  batch_set_image_overlay_to_video,
                                  batch_set_text_watermark_to_video, load_video, clip_video_by_moviepy,
                                  set_background_music_to_video,
                                  flip_video_vertically, flip_video_horizontally)


class BaseVideo(ABC):
    def __init__(self,
                 video_groups: Any,
                 num_outputs: int = 1,
                 import_subtitle: bool = False,
                 subtitle_path: str = '',
                 keep_original_audio: bool = True,
                 auto_match_audio: bool = False,
                 audio_path: str = '',
                 audio_status: bool = False,
                 total_duration: int = 0,
                 speed: float = 1.0,
                 output_dir: str = './output',
                 video_priority: bool = True,
                 resolution: tuple = None,  # (width, height)
                 set_title: bool = False,
                 set_background_music: bool = False,
                 set_overlay: bool = False,
                 set_cover: bool = False,
                 set_watermark: bool = False,
                 set_filters: bool = False,
                 **kwargs
                 ):
        """
        :param video_groups: 视频文件列表
        :param num_outputs: 生成数量, 默认为1
        :param import_subtitle: 是否导入字幕
        :param subtitle_path: 字幕文件路径
        :param keep_original_audio: 是否保留原音频
        :param auto_match_audio: 是否自动匹配音频
        :param audio_path: 音频文件路径
        :param audio_status: 音频状态
        :param total_duration: 总时长
        :param speed: 速度
        :param output_dir: 输出目录
        :param video_priority: 视频优先级; 视频长度比音频短时，循环视频匹配音频时长
        :param resolution: 分辨率
        :param set_title: 是否设置标题
        :param set_background_music: 是否设置背景音乐
        :param set_overlay: 是否设置叠加层
        :param set_cover: 是否设置封面
        :param set_watermark: 是否设置水印
        :param set_filters: 是否设置滤镜
        :param kwargs: 其他参数: 如字幕位置、字幕大小、字幕颜色等
        """
        super().__init__()
        self.video_groups = video_groups  # 视频文件列表
        self.num_outputs = num_outputs  # 生成数量
        self.import_subtitle = import_subtitle  # 是否导入字幕
        self.subtitle_path = subtitle_path  # 字幕文件路径
        self.keep_original_audio = keep_original_audio  # 是否保留原音频
        self.auto_match_audio = auto_match_audio  # 是否自动匹配音频
        self.audio_path = self._random_get_audio(audio_path)  # 每次随机选择一个音频文件
        self.audio_status = audio_status  # 音频状态
        self.total_duration = total_duration  # 总时长; 0表示不限制
        self.speed = speed  # 速度 1.0表示原速
        self.output_dir = os.path.join(output_dir, datetime.now().strftime('%Y-%m-%d'), "视频合成")  # 输出目录
        self.video_priority = video_priority  # 视频优先级
        self.resolution = resolution  # 分辨率
        self.temp_dir = os.path.join(tempfile.gettempdir(), datetime.now().strftime('%Y-%m-%d'))  # 临时目录
        self.kwargs = kwargs
        self.set_title = set_title  # 是否设置标题
        self.set_background_music = set_background_music  # 是否设置背景音乐
        self.set_overlay = set_overlay  # 是否设置叠加层
        self.set_cover = set_cover  # 是否设置封面
        self.set_watermark = set_watermark  # 是否设置水印
        self.set_filters = set_filters
        self.max_workers = 5  # 最大线程数

        self.tasks = []  # 任务列表
        os.makedirs(self.temp_dir, exist_ok=True)
        os.makedirs(self.output_dir, exist_ok=True)


    def __del__(self):
        for l in os.listdir(self.temp_dir):
            try:
                os.remove(l)
            except Exception as e:
                pass

    def _move_to_output_dir(self) -> None:
        log.debug("开始同步视频文件.")
        for filename in self.tasks:
            log.debug(f"开始同步：{filename}")
            if filename.lower().endswith('.mp4') and os.path.exists(filename):
                target_file_path = os.path.join(self.output_dir, os.path.basename(filename))
                log.debug(target_file_path)
                try:
                    shutil.copy(filename, target_file_path)
                    while True:
                        if os.path.exists(target_file_path):
                            log.debug(f"同步完成：{filename}")
                            break
                        time.sleep(1)
                except Exception as e:
                    log.debug(f"移动文件失败：{e}")


    def __is_audio_file(self, filename: str) -> bool:
        audio_extensions = {'.mp3', '.wav', '.aac', '.flac', '.ogg', '.m4a'}
        return os.path.splitext(filename)[1].lower() in audio_extensions


    def _random_get_audio(self, video_path: Union[str, Path]) -> Any:
        try:
            if os.path.isfile(video_path) and self.__is_audio_file(video_path):
                audio_file = video_path
            elif os.path.isdir(video_path) and any([self.__is_audio_file(f) for f in os.listdir(video_path)]) and self.auto_match_audio:
                audio_file = random.choice([f for f in os.listdir(video_path) if self.__is_audio_file(f)])
            else:
                return None
            return audio_file
        except Exception as e:
            log.debug(f"随机获取音频失败：{e}")
            return None


    def generate_combinations(self) -> List[List[str]]:
        """
            根据规则，从任务中生成符合要求的文件组合
        :return: List[List[str]] 每个组合包含一个来自每个任务的文件
        """
        log.debug("根据条件预处理视频")
        results = []
        task_files_pool = []

        # 处理任务池
        for task in self.video_groups:
            if task.get("rule") == "unique":
                task_files_pool.append(list(task["files"]))
            else:
                task_files_pool.append(task["files"])

        # 使用线程池来并发处理每个组合的生成
        with ThreadPoolExecutor() as executor:
            future_to_combination = []

            # 生成每个组合并通过线程池处理
            for _ in range(self.num_outputs):
                future = executor.submit(self._generate_single_combination, self.video_groups, task_files_pool)
                future_to_combination.append(future)

            # 获取所有任务的结果
            for future in as_completed(future_to_combination):
                results.append(future.result())

        log.debug("预处理完成.")
        return results


    def _generate_single_combination(self, tasks: List[Dict], task_files_pool: List[List[str]]) -> List[str]:
        """
        为每个组合生成一个独立的任务处理
        :param tasks: 每项任务包含 { files: [...], rule: "random"/"unique", ... }
        :param task_files_pool: 每个任务的文件池
        :return: 组合后的文件列表
        """
        current_combination = []
        for i, task in enumerate(tasks):
            rule = task.get("rule", "random")
            pool = task_files_pool[i]
            choice = ""

            if rule == "unique" and not pool:
                return current_combination
            if rule == "unique":
                choice = pool.pop(0)
            else:
                choice = random.choice(pool)

            # 复制文件到临时目录
            choice = shutil.copy(choice, os.path.join(self.temp_dir, os.path.basename(choice)))
            log.debug(f"开始处理：{choice}")

            # --------------- 滤镜 ---------------
            # ✅ TODO: 实现滤镜功能

            # 按照开始时间截取
            start_time = task.get("start_time", 0)
            start_time = start_time if start_time < load_video(choice).get("duration") else 0
            if start_time:
                log.debug("预处理: 按照开始时间截取")
                clip_video_by_moviepy(choice, choice, start_time, load_video(choice).get("duration"))

            # 按照分镜时长截取
            if task.get("duration"):
                log.debug("预处理: 按照分镜时长截取")
                video_duration = load_video(choice).get("duration")
                clip_video_by_moviepy(choice, choice, 0, min(task.get("duration"), video_duration))

            # 翻转操作
            if task.get("flip") == "h":
                log.debug("预处理: 水平翻转")
                flip_video_horizontally(choice, choice)
            elif task.get("flip") == "v":
                log.debug("预处理: 垂直翻转")
                flip_video_vertically(choice, choice)
            elif task.get("flip") == "random":
                log.debug("预处理: 随机翻转")
                random.choice([flip_video_horizontally, flip_video_vertically])(choice, choice)

            # 音频合并
            if task.get("audio") and (os.path.isfile(task.get("audio", "")) or os.path.isdir(task.get("audio", ""))):
                log.debug("预处理: 音频合并")
                audio_path = self._random_get_audio(task.get("audio"))
                if audio_path:
                    set_background_music_to_video(choice, audio_path, choice, task.get("audio_volume", 1.0),
                                                  task.get("keep_original_audio", True), task.get("video_priority", True))

            # --------------- 转场特效 -------------
            # ✅ TODO: 自动剪辑：实现转场特效功能

            current_combination.append(choice)

        return current_combination


    def processor(self):
        """
        生成视频
        """
        # 根据条件筛选视频文件
        self.tasks = self.generate_combinations()
        self.preprocessing()
        # 合并视频
        log.debug("准备合并视频.")
        self.tasks = batch_merge_videos(self.tasks, self.temp_dir, self.keep_original_audio)
        log.debug("批量合并视频完成.")
        # 视频加速
        if self.speed != 1.0:
            log.debug("加速视频.")
            self.tasks = batch_speed_up_videos(self.tasks, self.temp_dir, self.speed, self.keep_original_audio)
            log.debug("加速视频完成.")
        # 视频裁剪
        if self.total_duration:
            log.debug("准备裁剪视频.")
            self.tasks = batch_clip_video(self.tasks, self.temp_dir, 0, self.total_duration)
            log.debug("裁剪视频完成.")
        # 调整视频分辨率
        if self.resolution:
            log.debug("准备调整分辨率.")
            self.tasks = batch_resize_videos(self.tasks, self.temp_dir, self.resolution)
            log.debug("调整分辨率完成.")
        # 导入字幕
        if self.import_subtitle:
            log.debug("准备导入字幕.")
            assert os.path.exists(self.subtitle_path), f"字幕文件不存在: {self.subtitle_path}"
            self.tasks = batch_set_srt_to_video(
                self.tasks, self.subtitle_path, self.temp_dir, self.kwargs.get('import_subtitle_position').get("bottom_margin", 50),
                self.kwargs.get('import_subtitle_position').get("font_path", r"C:\Windows\Fonts\simsun.ttc"), self.kwargs.get('import_subtitle_position').get("font_size", 36),
                self.kwargs.get('import_subtitle_position').get("font_color", "white"), self.kwargs.get('import_subtitle_position').get("horizontal_margin", 20)
            )
            log.debug("导入字幕完成.")

        # 设置背景音乐
        if self.set_background_music:
            log.debug("添加背景音乐.")
            self.tasks = batch_set_background_music_to_video(
                self.tasks, self.kwargs.get("set_background_music_position").get('audio_path'), self.temp_dir, self.kwargs.get("set_background_music_position").get('volume', 1.0),
                self.kwargs.get("set_background_music_position").get('keep_original_audio', True), self.kwargs.get("set_background_music_position").get('video_priority', True)
            )
            log.debug("添加背景音乐完成.")
        # 设置叠加层
        if self.set_overlay:
            log.debug("贴片.")
            self.tasks = batch_set_image_overlay_to_video(self.tasks, self.kwargs.get("set_overlay_position").get("image_path"),
                                                          self.temp_dir, self.kwargs.get("set_overlay_position").get("overlay_duration", 1.0))
            log.debug("贴片完成.")
        # 设置封面
        if self.set_cover:
            log.debug("设置封面.")
            self.tasks = batch_set_video_cover(self.tasks, self.kwargs.get("set_cover_position").get("cover_path"), self.temp_dir)
            log.debug("设置封面完成.")

        # 设置水印
        if self.set_watermark:
            log.debug("设置水印.")
            self.tasks = batch_set_text_watermark_to_video(
                self.tasks, self.kwargs.get("set_watermark_position").get("watermark_text"), self.temp_dir,
                self.kwargs.get("set_watermark_position").get("x"), self.kwargs.get("set_watermark_position").get("y"),
                self.kwargs.get("set_watermark_position").get("font_path", r"C:\Windows\Fonts\simsun.ttc"), self.kwargs.get("set_watermark_position").get("font_size", 36),
                self.kwargs.get("set_watermark_position").get("font_color", "white")
               )
            log.debug("设置水印完成.")

        # 设置标题
        if self.set_title:
            log.debug("设置标题.")
            self.tasks = batch_set_subtitle_to_video(
                self.tasks, self.kwargs.get("set_title_position").get("subtitle_text"), self.temp_dir, self.kwargs.get("set_title_position").get("bottom_margin", 50),
                self.kwargs.get("set_title_position").get("font_path", r"C:\Windows\Fonts\simsun.ttc"), self.kwargs.get("set_title_position").get("font_size", 36),
                self.kwargs.get("set_title_position").get("font_color", "white"), self.kwargs.get("set_title_position").get("subtitle_duration", 1.0)
                 )
            log.debug("设置标题完成.")

        # 配音
        if self.audio_status:
            log.debug("配音.")
            if self.audio_path:
                self.tasks = batch_set_background_music_to_video(
                    self.tasks,self.audio_path, self.temp_dir, self.speed, self.keep_original_audio, self.video_priority
                )
            log.debug("配音完成.")

        if self.set_filters:
            pass  # ✅ TODO: 实现滤镜功能

        self.postprocessing()  # 后处理
        # 输出视频
        log.debug("开始输出视频.")


    def preprocessing(self):
        """预处理：对 self.tasks 进行预处理"""
        pass


    def postprocessing(self):
        """后处理：对 self.tasks 进行后处理"""
        pass


    def generate(self):
        """ 生成视频 """
        try:
            log.debug("开始合成视频")
            self.processor()
            self._move_to_output_dir()
            log.debug("合成视频完成")
            os.system(f"start {self.output_dir}")
        except Exception as e:
            log.error(traceback.format_exc())
            log.error(f"合成视频失败: {e}")
